#ifndef SOS_VFS_H
#define SOS_VFS_H

#include <libut.h>
#include <sos.h>

#include "list.h"

#define SOS_VFS_SUCCESS  (0)
#define SOS_VFS_OOM      (1)
#define SOS_VFS_INVAL    (2)
#define SOS_VFS_NOENT    (3)
#define SOS_VFS_PERM     (4)
#define SOS_VFS_REMOUNT  (5)
#define SOS_VFS_SEGFAULT (6)

/* Maximum open FDs per process */
#define SOS_MAX_FD       (1024)

/* Forward declaration from process.h */
typedef struct sos_pcb sos_pcb;

typedef struct sos_vfs sos_vfs;
typedef struct sos_mountpoint sos_mountpoint;
typedef struct sos_mount sos_mount;
typedef struct sos_filesystem sos_filesystem;
typedef struct sos_fd sos_fd;

/* Process metadata for SOS kernel space */

// File descriptor: goes into PCB, contains seek point (byte offset)
//   - and points to... something? hmm.
struct sos_fd {
    int proc_fd;       /* Whatever descriptor we gave the process in open    */
    seL4_Word fs_fd;   /* Whatever descriptor fs->mount->open gave us        */
    sos_mount *fs;     /* XXX Need to make sure FS cleanup destroys danglers */
    UT_hash_handle hh; /* This lets us create hash tables of FDs             */
};


// VFS needs some concrete notion of:

// - Mountpoint. Path resolution means going through mountpoints trie-style.
struct sos_mountpoint {
    const char *path;
    sos_mount *mount;
};

// - Itself. No global state allowed. Also, this earns us chroot for free.
struct sos_vfs {
    // XXX M5: Trie this
    sos_mountpoint console;
    sos_mountpoint nfs;
};

// - A mounted filesystem. Function pointers for the basic filesystem operations
struct sos_mount {
    int (*open)(sos_pcb *, const char*, fmode_t, int, seL4_Word*);
    int (*close)(sos_pcb *, seL4_Word);
    int (*read)(sos_pcb *, seL4_Word, char*, size_t);
    int (*write)(sos_pcb *, seL4_Word, char*, size_t);
    int (*getdirent)(sos_pcb *, int, size_t);
    int (*stat)(sos_pcb *, const char*);
};

// - Filesystem (driver). Provides mount and unmount operations.
//   Struct is populated by concrete filesystem implementations, like console.h.
struct sos_filesystem {
    /* The mount function receives some FS-specific string, and memory
       to store the resulting mount. Can return its own error
       codes. */
    int (*mount)(sos_mount *mount, const char *fs_data);
    int (*umount)(sos_mount *mount, const char *fs_data);
};

/* Filesystem functions for SOS kernel space. */

// The concrete FS provides us a mount function, and we push the
// resulting mount plus whatever else into our datastructures.
int sos_vfs_mount(sos_vfs *vfs, const char *mpoint, sos_filesystem *fs,
                  const char *fs_data);

int sos_vfs_open(sos_pcb *pcb, sos_vfs *vfs, const char *path, fmode_t mode);
int sos_vfs_close(sos_pcb *pcb, sos_vfs *vfs, int proc_fd);
int sos_vfs_read(sos_pcb *pcb, sos_vfs *vfs, int proc_fd,
                 seL4_Word proc_vaddr, size_t nbyte);
int sos_vfs_write(sos_pcb *pcb, sos_vfs *vfs, int proc_fd,
                  seL4_Word proc_vaddr, size_t nbyte);
int sos_vfs_stat(sos_pcb *pcb, sos_vfs *vfs, const char *path);
int sos_vfs_getdirent(sos_pcb *pcb, sos_vfs *vfs,
                      int pos, size_t max);

// The concrete FS provides us a umount function, and we remove the
// existing mountpoint from our datastructures.
// XXX This is a secondary concern for now.
// int sos_umount(sos_vfs *vfs, char *mpoint, sos_filesystem *fs,
//                const char *fs_data);
// XXX How to trash all open files? Wait for access? Problem - mount
//     will be free'd, null deref.  Should probably aggressively trash
//     FDs. Store (PID, FD) <-> FS links in the file table.

/* VFS functions for SOS kernel space */
int sos_vfs_init(sos_vfs **vfs);

// Console ''driver'' will just implement VFS interface
// - Resource control can be handled in its open / close callbacks
// - Assume the FDs given to open / close are valid. SOS must check them.

// NFS ''driver'' will just implement this VFS interface.
// Most of the work is done in stat etc.

#endif // SOS_VFS_H
